import { reactive } from 'vue'

interface Opts {
  estimated: number
  total: number
  overscan: number
}

function bisect(arr: number[], target: number) {
  let l = 0, r = arr.length - 1
  while (l <= r) {
    const m = (l + r) >> 1
    if (arr[m] === target) return m
    arr[m] < target ? (l = m + 1) : (r = m - 1)
  }
  return Math.max(0, l - 1)
}

export function useRowStore(opts: Opts) {
  const state = reactive({
    heights: Array(opts.total).fill(opts.estimated) as number[],
    prefix: [] as number[],
    start: 0,
    end: 0
  })

  const recompute = () => {
    state.prefix.length = opts.total
    let acc = 0
    for (let i = 0; i < opts.total; i++) {
      state.prefix[i] = acc
      acc += state.heights[i]
    }
  }
  recompute()

  function setRowHeight(i: number, h: number) {
    if (state.heights[i] !== h) {
      state.heights[i] = h
      recompute()
    }
  }

  function updateVisible(top: number, vpH: number) {
    const first = bisect(state.prefix, top)
    const last = bisect(state.prefix, top + vpH)
    state.start = Math.max(0, first - opts.overscan)
    state.end = Math.min(opts.total - 1, last + opts.overscan)
  }

  
  /** 行数变动时重置 */
  function reset(total: number) {
    state.heights = Array(total).fill(opts.estimated)
    recompute()
  }


  function forceRemeasure() {
    recompute()
  }

  return { state, setRowHeight, updateVisible, forceRemeasure, reset }
}
